package wechat_sdk_go

import (
	"encoding/json"
	"errors"
	"sync"
	"time"
)

type AccessToken struct {
	t            *Token
	tokenKey     string
	appid        string
	appsecret    string
	verifyTicket VerifyTicketInterface
	rw           sync.Mutex
}

func NewComponentAccessToken(appid string, appsecret string, verifyTicket VerifyTicketInterface) *AccessToken {
	return &AccessToken{
		new(Token),
		"component_access_token",
		appid,
		appsecret,
		verifyTicket,
		sync.Mutex{},
	}
}

func (at *AccessToken) getComponentToken() ([]byte, error) {
	url := "cgi-bin/component/api_component_token"

	js := make(map[string]interface{})

	js["component_appid"] = at.appid
	js["component_appsecret"] = at.appsecret
	js["component_verify_ticket"] = at.verifyTicket.Get(at.appid)

	request := NewBaseRequest()

	rep, err := request.Post(url, HttpOption{
		js,
		nil,
	})

	return handlerRequestResult(rep, err)
}

func (at *AccessToken) GetToken() (*Token, error) {
	at.rw.Lock()
	defer at.rw.Unlock()

	token := at.t

	nowTime := time.Now().Unix()

	if nowTime < token.ExpiresIn {
		return token, nil
	}

	response, err := at.getComponentToken()

	if nil != err {
		return nil, err
	}

	var responseMap map[string]interface{}
	err = json.Unmarshal(response, &responseMap)

	if nil != err {
		return nil, err
	}

	componentAccessToken, ok := responseMap["component_access_token"]

	if !ok {
		return nil, errors.New(string(response))
	}

	token.AccessToken = componentAccessToken.(string)
	token.ExpiresIn = nowTime + int64(responseMap["expires_in"].(float64))

	return token, nil
}

func (at *AccessToken) Refresh() (*Token, error) {
	return at.GetToken()
}

func (at *AccessToken) GetTokenKey() string {
	return at.tokenKey
}
